package rtool

import (
	"cmp"
	"fmt"
	"sync"
)

// CompareIntersection 切片交集，返回：src 和 tar 中，都有的元素。
func CompareIntersection[T cmp.Ordered](src []T, tar []T) []T {
	var rt = make([]T, 0, 1024)
	var tempMap = sync.Map{}
	for j := 0; j < len(tar); j++ {
		tempMap.Store(fmt.Sprint(tar[j]), byte(1))
	}
	for i := 0; i < len(src); i++ {
		if _, ok := tempMap.Load(fmt.Sprint(src[i])); ok {
			rt = append(rt, src[i])
		}
	}
	return rt
}

// CompareSubtractive 切片减集，返回：从 src 中去除 tar 后的元素。
func CompareSubtractive[T cmp.Ordered](src []T, tar []T) []T {
	var rt = make([]T, 0, 1024)
	var tempMap = sync.Map{}
	for j := 0; j < len(tar); j++ {
		tempMap.Store(fmt.Sprint(tar[j]), byte(1))
	}
	for i := 0; i < len(src); i++ {
		if _, ok := tempMap.Load(fmt.Sprint(src[i])); false == ok {
			rt = append(rt, src[i])
		}
	}
	return rt
}

// CompareDifference 切片差集，返回：1先取 src 和 tar 的交集L，2合并 src 和 tar ，3合并结果去重后删除交集L。
func CompareDifference[T cmp.Ordered](src []T, tar []T) []T {
	var rt = make([]T, 0, 1024)
	temp := CompareIntersection(src, tar)
	var tempMap = sync.Map{}
	for _, d := range temp {
		tempMap.Store(fmt.Sprint(d), byte(1))
	}
	for i := 0; i < len(src); i++ {
		if _, ok := tempMap.Load(fmt.Sprint(src[i])); false == ok {
			rt = append(rt, src[i])
		}
	}
	for i := 0; i < len(tar); i++ {
		if _, ok := tempMap.Load(fmt.Sprint(tar[i])); false == ok {
			rt = append(rt, tar[i])
		}
	}
	return rt
}

// CompareUnion 切片并集，返回：合并 src 和 tar ，然后去重的结果。
func CompareUnion[T cmp.Ordered](src []T, tar []T) []T {
	var rt = make([]T, 0, 1024)
	var tempMap = sync.Map{}
	for i := 0; i < len(src); i++ {
		if _, ok := tempMap.Load(fmt.Sprint(src[i])); ok {
			continue
		}
		tempMap.Store(fmt.Sprint(src[i]), byte(1))
		rt = append(rt, src[i])
	}

	for i := 0; i < len(tar); i++ {
		if _, ok := tempMap.Load(fmt.Sprint(tar[i])); ok {
			continue
		}
		tempMap.Store(fmt.Sprint(tar[i]), byte(1))
		rt = append(rt, tar[i])
	}
	return rt
}

// BinSearch 二分查找法，查找前，arr必须先按照从小到大排序
// 找到了，返回对应的下标；没有找到，返回-1
func BinSearch[T cmp.Ordered](arr []T, value T) int {
	length := len(arr)
	left := 0
	right := length - 1
	for i := 0; i < length; i++ {
		er := (left + right) / 2
		_rt := cmp.Compare(value, arr[er])
		if _rt == 1 {
			left = er + 1
		} else if _rt == -1 {
			right = er - 1
		} else {
			return er
		}
	}
	return -1
}
